﻿/*
 * modbusmap.cpp
 *
 *  Created on: 2019-4-14
 *      Author: work
 */

#include <dm/export.hpp>

#define DM_API_PROTOCOL DM_API_EXPORT

#include <dm/protocol/modbusmap.hpp>
#include <iostream>
#include <dm/os/log/logger.hpp>

static const char* logModule = "dm.protocol.CModbusMap";

using namespace std;

namespace dm{
namespace protocol{

CModbusMap::CModbusMap():m_title(),m_desc(),m_plcAddress(false),
		m_regs(),m_statuses(),m_discretes(),m_measures(),m_cumulants(),m_parameters(),m_rmtctls(){
}

static void showItem( const CModbusMapItem* item ){
	cout <<' '<<item->desc()
			<<" 名字:"<<item->name()
			<<" 码:"<<item->fun()
			<<" 地址:"<<item->address();
}

static void showDataItem( const CModbusMapDataItem* item ){
	cout <<" 存盘:"<<(item->ifStore()?1:0)
			<<" 时标:"<<(item->ifGenTimed()?1:0)
			<<" 上报:"<<(item->ifReportTimed()?1:0);
}

CModbusMap::~CModbusMap(){
	for( unsigned int i=0;i<m_statuses.size();++i )
		delete m_statuses[i];
	for( unsigned int i=0;i<m_discretes.size();++i )
		delete m_discretes[i];
	for( unsigned int i=0;i<m_measures.size();++i )
		delete m_measures[i];
	for( unsigned int i=0;i<m_cumulants.size();++i )
		delete m_cumulants[i];
	for( unsigned int i=0;i<m_parameters.size();++i )
		delete m_parameters[i];
	for( unsigned int i=0;i<m_rmtctls.size();++i )
		delete m_rmtctls[i];
}

bool CModbusMap::init( const char* file,const bool& debug ){
	TiXmlDocument xml;

	if( debug )
		cout <<"打开配置文件"<<file<<"...";
	if( xml.LoadFile(file)==false ){
		if( debug )
			cout <<"加载xml失败:"<<xml.ErrorDesc()<<endl;
		return false;
	}

	if( debug )
		cout <<"\n查找根节点modbus-map...";
	const TiXmlElement* cfg = xml.RootElement();
	if( cfg==NULL || strcmp(cfg->Value(),"modbus-map")!=0 ){
		if( debug )
			cout <<"失败"<<endl;
		return false;
	}

	m_title = cfg->Attribute("title");
	m_desc = cfg->Attribute("desc");

	if( debug )
		cout <<"\n标题:"<<m_title<<"\n描述:"<<m_desc;

	const char* c = cfg->Attribute("address-type");
	if( c ){
		if( strcmp(c,"plc")==0 ){
			m_plcAddress = true;
			if( debug )
				cout <<"\naddress-type:plc";
		}else{
			if( debug )
				cout <<"\n未知地址类型"<<c;
			return false;
		}
	}

	if( debug )
		cout <<"\n查找call标签...";
	int i,j,k;
	const TiXmlElement* e = cfg->FirstChildElement("call");
	while( e ){
		if( debug )
			cout <<"\n处理call标签...";
		if( e->Attribute("fun",&i)==NULL ){
			if( debug )
				cout <<"\n错误：未定义fun属性";
			return false;
		}
		if( e->Attribute("address",&j)==NULL ){
			if( debug )
				cout <<"\n错误：未定义address属性";
			return false;
		}
		if( e->Attribute("quantity",&k)==NULL ){
			if( debug )
				cout <<"\n错误：未定义quantity属性";
			return false;
		}

		if( (i==3||i==4)&&k>100 ){
			if( debug )
				cout <<"\n错误：数据个数超长 fun:"<<i<<" address:"<<j<<" quantity:"<<k<<"(>100)"<<endl;
			return false;
		}

		if( m_plcAddress ){
			if( m_regs.addSegment(CModbusRegs::fun_t(i),j-1,k)==false ){
				if( debug )
					cout <<"\n错误：添加到分段失败";
				return false;
			}
		}else{
			if( m_regs.addSegment(CModbusRegs::fun_t(i),j,k)==false ){
				if( debug )
					cout <<"\n错误：添加到分段失败";
				return false;
			}
		}

		if( debug )
			cout <<"\n fun："<<i<<" address:"<<j<<" quantity:"<<k;

		e = e->NextSiblingElement("call");
	}

	if( debug )
		cout <<"\n查找status标签...";
	e = cfg->FirstChildElement("status");
	while( e ){
		CModbusMapStatus* status = new CModbusMapStatus;
		if( status->init(e,m_plcAddress)==false ){
			if( debug )
				cout <<"\n"<<m_statuses.size()<<":失败";
			delete status;
			return false;
		}

		if( debug ){
			cout <<'\n'<<m_statuses.size();
			showItem(status);

			cout <<" 位:"<<status->bitOffset()
						<<" 位长:"<<status->bitLen()
						<<" 合:"<<status->valueOn()<<" "<< status->onDesc()
						<<" 分:"<<status->valueOff()<<" "<< status->offDesc()
						<<" 无效合:"<<status->valueInvOn()<<" "<< status->invOnDesc()
						<<" 无效分:"<<status->valueInvOff()<<" "<< status->invOffDesc()
						<<" 无效值:"<<status->invalidValue();

			showDataItem(status);
		}
		m_statuses.push_back(status);

		e = e->NextSiblingElement("status");
	}

	if( debug )
		cout <<"\n查找discrete标签...";
	e = cfg->FirstChildElement("discrete");
	while( e ){
		if( debug )
			cout <<"\n处理discrete标签...";
		CModbusMapDiscrete* discrete = new CModbusMapDiscrete;
		if( discrete->init(e,m_plcAddress)==false ){
			if( debug )
				cout <<"\n"<<m_discretes.size()<<":失败";
			delete discrete;
			return false;
		}

		if( debug ){
			cout <<'\n'<<m_discretes.size();
			showItem(discrete);

			cout <<" 位:"<<discrete->bitOffset()
						<<" 位长:"<<discrete->bitLen()
						<<" 基值:"<<discrete->valueBase()
						<<" 无效值:"<<discrete->invalidValue()
						<<" 值:"<<discrete->valueDescs().size()<<"(";
			for( unsigned int i=0;i<discrete->valueDescs().size();++i )
				cout <<discrete->valueDescs()[i]<<",";
			cout <<")";

			showDataItem(discrete);
		}
		m_discretes.push_back(discrete);

		e = e->NextSiblingElement("discrete");
	}

	if( debug )
		cout <<"\n查找measure标签...";
	e = cfg->FirstChildElement("measure");
	while( e ){
		CModbusMapMeasure* measure = new CModbusMapMeasure;
		if( measure->init(e,m_plcAddress)==false ){
			if( debug )
				cout <<"\n"<<m_measures.size()<<":失败";
			delete measure;
			return false;
		}

		if( debug ){
			cout <<'\n'<<m_measures.size();
			showItem(measure);

			cout <<" 类型:"<<measure->type()
						<<" 基值:"<<measure->base()
						<<" 系数:"<<measure->coef()
						<<" 变化:"<<measure->delta()
						<<" 单位:"<<measure->unit();

			showDataItem(measure);
		}

		m_measures.push_back(measure);

		e = e->NextSiblingElement("measure");
	}

	if( debug )
		cout <<"\n查找cumulant标签...";
	e = cfg->FirstChildElement("cumulant");
	while( e ){
		CModbusMapCumulant* cumulant = new CModbusMapCumulant;
		if( cumulant->init(e,m_plcAddress)==false ){
			if( debug )
				cout <<"\n"<<m_cumulants.size()<<":失败";
			delete cumulant;
			return false;
		}

		if( debug ){
			cout <<'\n'<<m_cumulants.size();
			showItem(cumulant);

			cout <<" 类型:"<<cumulant->type()
						<<" 满码:"<<cumulant->maxCode()
						<<" 系数:"<<cumulant->coef()
						<<" 变化:"<<cumulant->delta();

			showDataItem(cumulant);
		}

		m_cumulants.push_back(cumulant);

		e = e->NextSiblingElement("cumulant");
	}

	if( debug )
		cout <<"\n查找parameter标签...";
	e = cfg->FirstChildElement("parameter");
	while( e ){
		CModbusMapParameter* paramter = new CModbusMapParameter;
		if( paramter->init(e,m_plcAddress)==false ){
			if( debug )
				cout <<"\n"<<m_parameters.size()<<":失败";
			delete paramter;
			return false;
		}

		if( debug ){
			cout <<'\n'<<m_parameters.size();
			showItem(paramter);

			cout <<" 类型:"<<paramter->type();
		}

		m_parameters.push_back(paramter);

		e = e->NextSiblingElement("parameter");
	}

	if( debug )
		cout <<"\n查找rmtctl标签...";
	e = cfg->FirstChildElement("remote-ctl");
	while( e ){
		CModbusMapRmtctl* rmtctl = new CModbusMapRmtctl;
		if( rmtctl->init(e,m_plcAddress)==false ){
			if( debug )
				cout <<"\n"<<m_rmtctls.size()<<":失败";
			delete rmtctl;
			return false;
		}

		if( debug ){
			cout <<'\n'<<m_rmtctls.size();
			showItem(rmtctl);

			cout <<" 位:"<<rmtctl->bitOffset()
						<<" 位长:"<<rmtctl->bitLen()
						<<" 控分:"<<rmtctl->valueOpen()<<" "<< rmtctl->openDesc()
						<<" 控合:"<<rmtctl->valueClose()<<" "<< rmtctl->closeDesc()
						<<" 预控分:"<<rmtctl->valuePreOpen()<<" "<< rmtctl->preOpenDesc()
						<<" 预控合:"<<rmtctl->valuePreClose()<<" "<< rmtctl->preCloseDesc()
						<<" 参考功能码:"<<rmtctl->refFun()
						<<" 参考寄存器:"<<rmtctl->refAddress();
		}
		m_rmtctls.push_back(rmtctl);

		e = e->NextSiblingElement("remote-ctl");
	}

	if( debug )
		cout <<"\n校验状态量...";
	for( unsigned int i=0;i<m_statuses.size();++i ){
		if( m_regs.ifAddressed(m_statuses[i]->fun(),m_statuses[i]->address(),1)==false ){
			if( debug )
				cout <<"\n"<<i<<" 地址错误:"<<m_statuses[i]->desc()<<" fun:"<<m_statuses[i]->fun()<<" address:"<<m_statuses[i]->address()<<endl;
			return false;
		}
	}

	if( debug )
		cout <<"\n校验离散量...";
	for( unsigned int i=0;i<m_discretes.size();++i ){
		if( m_regs.ifAddressed(m_discretes[i]->fun(),m_discretes[i]->address(),1)==false ){
			if( debug )
				cout <<"\n"<<i<<" 地址错误:"<<m_discretes[i]->desc()<<" fun:"<<m_discretes[i]->fun()<<" address:"<<m_discretes[i]->address()<<endl;
			return false;
		}
	}

	if( debug )
		cout <<"\n校验测量量...";
	for( unsigned int i=0;i<m_measures.size();++i ){
		if( m_regs.ifAddressed(m_measures[i]->fun(),m_measures[i]->address(),CModbusMapItem::typeWords(m_measures[i]->type()))==false ){
			if( debug ){
				cout <<"\n"<<i<<" 地址错误:"<<m_measures[i]->desc()<<" fun:"<<m_measures[i]->fun()
					<<" address:"<<m_measures[i]->address()
					<<" type:"<<CModbusMapItem::typeString(m_measures[i]->type())<<endl;
			}
			return false;
		}
	}

	if( debug )
		cout <<"\n校验累计量...";
	for( unsigned int i=0;i<m_cumulants.size();++i ){
		if( m_regs.ifAddressed(m_cumulants[i]->fun(),m_cumulants[i]->address(),CModbusMapItem::typeWords(m_cumulants[i]->type()))==false ){
			if( debug ){
				cout <<"\n"<<i<<" 地址错误:"<<m_cumulants[i]->desc()<<" fun:"<<m_cumulants[i]->fun()
					<<" address:"<<m_cumulants[i]->address()
					<<" type:"<<CModbusMapItem::typeString(m_cumulants[i]->type())<<endl;
			}
			return false;
		}
	}

	if( debug )
		cout <<"\n校验参数...";

	if( debug )
		cout <<"\n校验远控...";
	for( unsigned int i=0;i<m_rmtctls.size();++i ){
		if( m_rmtctls[i]->refAddress()!=0xFFFF ){
			if( m_regs.ifAddressed(m_rmtctls[i]->refFun(),m_rmtctls[i]->refAddress(),1)==false ){
				if( debug ){
					cout <<"\n"<<i<<" 地址错误:"<<m_rmtctls[i]->desc()<<" fun:"<<m_rmtctls[i]->fun()
						<<" address:"<<m_rmtctls[i]->address()
						<<" refFun:"<<m_rmtctls[i]->refFun()
						<<" refAddress:"<<m_rmtctls[i]->refAddress();
				}
				return false;
			}
		}
	}

	if( debug )
		cout <<"\nmodbus-map加载成功"<<endl;

	return true;
}

/**
 * 状态量所属数据缓冲区是否更新
 * 如果接收到新的报文，则反馈更新过，否则未更新
 */
bool CModbusMap::isUpdatedStatus( int i )const{
	if( i<0 || i>=int(m_statuses.size()) )
		return false;

	return m_regs.isUpdated(m_statuses[i]->fun(),m_statuses[i]->address());
}

/**
 * 离散量所属数据缓冲区是否更新
 */
bool CModbusMap::isUpdatedDiscrete( int i )const{
	if( i<0 || i>=int(m_discretes.size()) )
		return false;

	return m_regs.isUpdated(m_discretes[i]->fun(),m_discretes[i]->address());
}

/**
 * 测量量所属数据缓冲区是否更新
 */
bool CModbusMap::isUpdatedMeasure( int i )const{
	if( i<0 || i>=int(m_measures.size()) )
		return false;

	return m_regs.isUpdated(m_measures[i]->fun(),m_measures[i]->address());
}

/**
 * 累计量所属数据缓冲区是否更新
 */
bool CModbusMap::isUpdatedCumulant( int i )const{
	if( i<0 || i>=int(m_cumulants.size()) )
		return false;

	return m_regs.isUpdated(m_cumulants[i]->fun(),m_cumulants[i]->address());
}

/**
 * 获取状态量值
 * i 索引号
 * debug 是否输出详细信息，用于调试
 */
dm::uint16 CModbusMap::valueStatus( int i,bool debug )const{
	const CModbusMapStatus* status = m_statuses[i];
	uint r;
	switch( status->fun() ){
	case dm::protocol::CFrameModbus::ReadCoilStatus:
		r = m_regs.get01(status->address());
		break;
	case dm::protocol::CFrameModbus::ReadInputStatus:
		r = m_regs.get02(status->address());
		break;
	case dm::protocol::CFrameModbus::ReadHoldReg:
		if( status->bitLen()==16 )
			r = m_regs.get03Uint16(status->address());
		else
			r = m_regs.get03Bit(status->address(),status->bitOffset());
		break;
	case dm::protocol::CFrameModbus::ReadInputReg:
		if( status->bitLen()==16 )
			r = m_regs.get04Uint16(status->address());
		else
			r = m_regs.get04Bit(status->address(),status->bitOffset());
		break;
	default:
		log().error(THISMODULE "状态量%d %s 未配置正确功能码%d",i,status->desc().c_str(),status->fun());

		if( status->invalidValue()<0 || status->invalidValue()>=4 )
			return 0;
		else
			return status->invalidValue();
	}

	if( r==status->valueOn() ){
		if( debug )
			log().info(THISMODULE "状态量%d %s fun%d[%d][%d,%d] %04X => On",i,status->desc().c_str(),status->fun(),status->address(),status->bitOffset(),status->bitLen(),r);
		return 2;
	}else if( r==status->valueOff() ){
		if( debug )
			log().info(THISMODULE "状态量%d %s fun%d[%d][%d,%d] %04X => Off",i,status->desc().c_str(),status->fun(),status->address(),status->bitOffset(),status->bitLen(),r);
		return 1;
	}else if( r==status->valueInvOff() ){
		if( debug )
			log().info(THISMODULE "状态量%d %s fun%d[%d][%d,%d] %04X => invOff",i,status->desc().c_str(),status->fun(),status->address(),status->bitOffset(),status->bitLen(),r);
		return 0;
	}else if( r==status->valueInvOn() ){
		if( debug )
			log().info(THISMODULE "状态量%d %s fun%d[%d][%d,%d] %04X => invOn",i,status->desc().c_str(),status->fun(),status->address(),status->bitOffset(),status->bitLen(),r);
		return 3;
	}

	if( status->invalidValue()<0 || status->invalidValue()>=4 ){
		if( debug )
			log().info(THISMODULE "状态量%d %s fun%d[%d][%d,%d] %04X => inv0",i,status->desc().c_str(),status->fun(),status->address(),status->bitOffset(),status->bitLen(),r);
		return 0;
	}else{
		if( debug )
			log().info(THISMODULE "状态量%d %s fun%d[%d][%d,%d] %04X => inv",i,status->desc().c_str(),status->fun(),status->address(),status->bitOffset(),status->bitLen(),r);
		return status->invalidValue();
	}
}

/**
 * 获取离散量的值
 */
dm::uint16 CModbusMap::valueDiscrete( int i,bool /*debug*/ )const{
	const CModbusMapDiscrete* discrete = m_discretes[i];
	switch( discrete->fun() ){
	case dm::protocol::CFrameModbus::ReadCoilStatus:
		return m_regs.get01(discrete->address());
	case dm::protocol::CFrameModbus::ReadInputStatus:
		return m_regs.get02(discrete->address());
	case dm::protocol::CFrameModbus::ReadHoldReg:
		return m_regs.get03Bit(discrete->address(),discrete->bitOffset());
	case dm::protocol::CFrameModbus::ReadInputReg:
		return m_regs.get04Bit(discrete->address(),discrete->bitOffset());
	default:
		log().error(THISMODULE "离散量%d %s 未知功能码%d",i,discrete->desc().c_str(),discrete->fun());
		return 0;
	}
}

static dm::float32 getValueByType( const dm::uint8* p,const CModbusMapItem::EDataType& type ){
	switch( type ){
	case CModbusMapItem::DtInt16:
		return CModbusRegs::toInt16(p);
	case CModbusMapItem::DtUint16:
		return *p;

	case CModbusMapItem::DtInt32:
		return CModbusRegs::toInt32(p);
	case CModbusMapItem::DtInt32Inv:
		return CModbusRegs::toInt32Inv(p);
	case CModbusMapItem::DtUint32:
		return CModbusRegs::toUint32(p);
	case CModbusMapItem::DtUint32Inv:
		return CModbusRegs::toUint32Inv(p);

	case CModbusMapItem::DtInt64:
		return CModbusRegs::toInt64(p);
	case CModbusMapItem::DtInt64Inv:
		return CModbusRegs::toInt64Inv(p);
	case CModbusMapItem::DtUint64:
		return CModbusRegs::toUint64(p);
	case CModbusMapItem::DtUint64Inv:
		return CModbusRegs::toUint64Inv(p);

	case CModbusMapItem::DtFloat32:
		return CModbusRegs::toFloat32(p);
	case CModbusMapItem::DtFloat32Inv:
		return CModbusRegs::toFloat32Inv(p);

	case CModbusMapItem::DtFloat64:
		return CModbusRegs::toFloat64(p);
	case CModbusMapItem::DtFloat64Inv:
		return CModbusRegs::toFloat64Inv(p);

	case CModbusMapItem::DtBcdUint16:
		return CModbusRegs::toBcdUint16(p);

	case CModbusMapItem::DtBcdUint32:
		return CModbusRegs::toBcdUint32(p);
	case CModbusMapItem::DtBcdUint32Inv:
		return CModbusRegs::toBcdUint32Inv(p);

	case CModbusMapItem::DtBcdUint64:
		return CModbusRegs::toBcdUint64(p);
	case CModbusMapItem::DtBcdUint64Inv:
		return CModbusRegs::toBcdUint64Inv(p);

	default:
		return 0;
	}
}

/**
 * 获取测量量的值
 */
dm::float32 CModbusMap::valueMeasure( int i,bool debug )const{
	const CModbusMapMeasure* measure = m_measures[i];
	const dm::uint8* r;

	switch( measure->fun() ){
	case dm::protocol::CFrameModbus::ReadHoldReg:
		r = m_regs.get03(measure->address());
		break;
	case dm::protocol::CFrameModbus::ReadInputReg:
		r = m_regs.get04(measure->address());
		break;
	default:
		log().warnning(THISMODULE "测量量%d %s 配置了无效功能码%d",i,measure->desc().c_str(),measure->fun());
		return 0;
	}

	float v = getValueByType(r,measure->type());

	if( debug ){
		log().info(THISMODULE "测量量%d %s fun%d[%d](%s)=%f[%02X %02X %02X %02X]",i,measure->desc().c_str(),measure->fun(),measure->address(),measure->typeString(measure->type()),
			v,r[0],r[1],r[2],r[3]);
	}

	return v;
}

dm::uint64 CModbusMap::valueCumulant( int i,bool debug )const{
	const CModbusMapCumulant* cumulant = m_cumulants[i];
	const dm::uint8* r;

	switch( cumulant->fun() ){
	case dm::protocol::CFrameModbus::ReadHoldReg:
		r = m_regs.get03(cumulant->address());
		break;
	case dm::protocol::CFrameModbus::ReadInputReg:
		r = m_regs.get04(cumulant->address());
		break;
	default:
		log().warnning(THISMODULE "累计量%d %s 配置了无效功能码%d",i,cumulant->desc().c_str(),cumulant->fun());
		return 0;
	}

	float v = getValueByType(r,cumulant->type());

	if( debug ){
		log().info(THISMODULE "累计量%d %s fun%d[%d](%s)=%f[%02X %02X %02X %02X]",i,cumulant->desc().c_str(),cumulant->fun(),cumulant->address(),cumulant->typeString(cumulant->type()),
			v,r[0],r[1],r[2],r[3]);
	}

	return v;
}

}
}
